//---------------------------------------------------------------------
// File: OrchestrationConductorExStep.cs
// 
// Summary: Replaces the orchestrationconductor step with code that uses the object model
//
// Copyright (c) Hammersmith & Fulham Bridge Partnership. All rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//---------------------------------------------------------------------

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Xml;
using System.Management;
using Microsoft.BizTalk.ExplorerOM;
using Microsoft.Services.BizTalkApplicationFramework.BizUnit;

namespace BizUnit.Extensions.BizTalk
{
	/// <summary>
	/// The OrchestrationConductorExStep may be used to stop/start an orchestration.
	/// This replaces the out of the box step with code that uses the OM.
	/// </summary>
	/// 
	/// <remarks>
	/// The following shows an example of the Xml representation of this test step.
	/// 
	/// <code escaped="true">
	/// <TestStep assemblyPath="BizUnitExtensions.BizTalk.dll" typeName="BizUnit.Extensions.BizTalk.OrchestrationConductorExStep">
	///		<DelayForCompletion>5</DelayForCompletion> <!-- Optional, seconds to delay for this step to complete -->
	///		<AssemblyName>BizUnitTest.Process</AssemblyName>
	///		<OrchestrationName>BizUnitTest.Process.SubmitToLedger</OrchestrationName>
	///		<Action>Start</Action>
	/// </TestStep>
	/// </code>
	///	<list type="table">
	///		<listheader>
	///			<term>Tag</term>
	///			<description>Description</description>
	///		</listheader>
	///		<item>
	///			<term>DelayForCompletion</term>
	///			<description>The delay before executing the step <para>(optional)</para></description>
	///		</item>
	///		<item>
	///			<term>AssemblyName</term>
	///			<description>The name of the assembly containing the orchestration, e.g. BizUnitTest.Process</description>
	///		</item>
	///		<item>
	///			<term>OrchestrationName</term>
	///			<description>The name of the orchestration to start/stop</description>
	///		</item>
	///		<item>
	///			<term>Action</term>
	///			<description>Start|Stop</description>
	///		</item>
	///	</list>
	///	</remarks>	
	 
	public class OrchestrationConductorExStep : ITestStep
	{
        //private variables
	    private BtsCatalogExplorer root;
	    private string connectionString;

		/// <summary>
		/// Enumerator for the action to apply on the orchestration
		/// </summary>
		public enum OrchestrationAction 
		{
			/// <summary>
			/// starts the orchestration
			/// </summary>
			Start,
			/// <summary>
			/// stops the orchestration
			/// </summary>
			Stop,

            Enlist,

            Unenlist,

            Bind,

            
		}

		/// <summary>
		/// ITestStep.Execute() implementation
		/// </summary>
		/// <param name='testConfig'>The Xml fragment containing the configuration for this test step</param>
		/// <param name='context'>The context for the test, this holds state that is passed beteen tests</param>
		public void Execute(XmlNode testConfig, Context context)
		{
			string assemblyName, orchestrationName, connectionString;

			try
			{
				assemblyName = context.ReadConfigAsString(testConfig, "AssemblyName");
				orchestrationName = context.ReadConfigAsString(testConfig, "OrchestrationName");
				connectionString = context.ReadConfigAsString(testConfig, "ConnectionString");
			}
			catch (Exception e)
			{
				context.LogInfo("There was an error while setting the parameters for this operation. Check that your test step includes arguments includes arguments for AssemblyName, OrchestrationName, and ConnectionString.");
				throw e;
			}

			OrchestrationAction action = (OrchestrationAction)Enum.Parse( typeof(OrchestrationAction), context.ReadConfigAsString(testConfig, "Action"), true );

			try 
			{

				ControlOrchestration(assemblyName, orchestrationName, action, connectionString, context);

				// Delay if necessary to allow the orchestration to start/stop
				int delayForCompletion = context.ReadConfigAsInt32(testConfig, "DelayForCompletion", true);
				if (delayForCompletion > 0)
				{
					context.LogInfo("Waiting for {0} seconds before recommencing testing.", delayForCompletion);
					Thread.Sleep(delayForCompletion*1000);
				}

			} 
			catch ( COMException e )
			{
				context.LogException( e );
				throw e;
			}
		}


		/// <summary>
		/// Starts orchestration with given name and assembly
		/// </summary>
		/// <param name="assemblyName">The name of the assembly</param>
		/// <param name="orchestrationName">The name of the orchestration</param>
		/// <param name="action">OrchestrationAction enumerator</param>
		/// <param name="connectionString">connection string to the BTS repository</param>
		/// <param name="context">global context variable</param>
		private void ControlOrchestration(string assemblyName, string orchestrationName, OrchestrationAction action, string connectionString, Context context)
		{
                switch(action)
                {
                    case OrchestrationAction.Start:
                        Start(assemblyName,orchestrationName,context);
                        break;

                    case OrchestrationAction.Stop:
                        Stop(assemblyName, orchestrationName, context);
                        break;

                    case OrchestrationAction.Enlist:
                        Enlist(assemblyName, orchestrationName, context);
                        break;

                    case OrchestrationAction.Unenlist:
                        Unenlist(assemblyName,orchestrationName,context);
                        break;

                    case OrchestrationAction.Bind:
                        Bind(assemblyName, orchestrationName, context);
                        break;

                    default:
                        context.LogError("Required Action not recognised");
                        break;

                }
		}

        private void Start(string assemblyName, string orchestrationName, Context context)
        {
            //We first need to check the status of the orchestration before doing 
            //any action 
            //This can be done in a generic QueryStatus method to check the correct
            //status before doing any action
            try
            {
                root = new BtsCatalogExplorer();
                root.ConnectionString = connectionString;

                BtsOrchestration orch = root.Assemblies[assemblyName].Orchestrations[orchestrationName];
                orch.AutoResumeSuspendedInstances = false;
                orch.Status = OrchestrationStatus.Started;
                //Try to commit the changes made so far. If it fails, roll-back 
                //all the changes.
                root.SaveChanges();
                context.LogInfo(String.Format("Orchestration {0} from Assembly {1} has been STARTED", orchestrationName, assemblyName));

            }
			catch (Exception e)
			{
				context.LogInfo(String.Format("Unable to {0} Orchestration {1} from Assembly {2}", userMessage[1], orchestrationName, assemblyName));
				context.LogException(e);
                throw e;
            }

        }

        private void Stop(string assemblyName, string orchestrationName, Context context)
        {

        }

        private void Enlist(string assemblyName, string orchestrationName, Context context)
        {

        }

        private void Unenlist(string assemblyName, string orchestrationName, Context context)
        {

        }

        private void Bind(string assemblyName, string orchestrationName, Context context)
        {

        }




	}
}
